package dnet

import (
	"fmt"
	"golang.org/x/net/proxy"
	"io"
	"net"
)

type TcpCliConn struct {
	addr          string
	dialProxyAddr string
	lastDialAddr  string
	conn          net.Conn

	OnConneceted  func(sender *TcpCliConn)
	OnConnectFail func(sender *TcpCliConn, err error)
}

func NewTcpCliConn() *TcpCliConn {
	return &TcpCliConn{}
}

func (this *TcpCliConn) ConfigRemoteAddr(s string) (isChanged bool) {
	if this.addr != s {
		this.addr = s
		return true
	}
	return false
}

func (this *TcpCliConn) Close() error {
	conn := this.conn
	if conn != nil {
		this.conn = nil
		return conn.Close()
	}
	return io.ErrClosedPipe
}

func (this *TcpCliConn) Read(buf []byte) (int, error) {
	conn := this.conn
	if conn == nil {
		return -1, io.ErrClosedPipe
	}
	return conn.Read(buf)
}

func (this *TcpCliConn) Write(buf []byte) (int, error) {
	conn := this.conn
	if conn == nil {
		return -1, io.ErrClosedPipe
	}
	return conn.Write(buf)
}

func (this *TcpCliConn) Open() error {
	proxyaddr := this.dialProxyAddr
	if len(proxyaddr) > 0 {
		this.lastDialAddr = fmt.Sprintf("%s,%s", proxyaddr, this.addr)
		d, err := proxy.SOCKS5("tcp", proxyaddr, nil, proxy.Direct)
		if err != nil {
			return err
		}
		conn, err := d.Dial("tcp", this.addr)
		if err != nil {
			evt := this.OnConnectFail
			if evt != nil {
				evt(this, err)
			}
			return err
		}
		this.conn = conn
	} else {
		this.lastDialAddr = fmt.Sprintf("%s", this.addr)
		conn, err := net.Dial("tcp", this.addr)
		if err != nil {
			evt := this.OnConnectFail
			if evt != nil {
				evt(this, err)
			}
			return err
		}
		this.conn = conn
		evt := this.OnConneceted
		if evt != nil {
			evt(this)
		}
	}
	return nil
}

func (this *TcpCliConn) CheckConnect() int {
	if this.conn != nil {
		return 0
	}
	err := this.Open()
	if err != nil {
		return -1
	}
	return 1
}
